<?php
/**
 * Slipstream :: Highly adaptive dependency injection framework
 * Copyright 2010-2011 Ian Unruh (Xerof3ar)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
namespace Slipstream\Infrastructure\Parameter;

use SplObjectStorage;
use Slipstream\Infrastructure\Parameter\MultiInjection\StrategyInterface;
use Slipstream\Infrastructure\Parameter\Policy\FilterInterface;
use Slipstream\Configuration\ParameterPolicy;
use Slipstream\Activation\SessionInterface;

/**
 *
 *
 * @author Ian Unruh (Xerof3ar) <ianunruh@gmail.com>
 * @since Class avaliable since release 1.0
 */
class PolicyResolver implements ResolverInterface
{
	protected $multiInjectionStrategy;
	protected $policyFilter;
	
	public function __construct(FilterInterface $policyFilter, StrategyInterface $multiInjectionStrategy)
	{
		$this->multiInjectionStrategy = $multiInjectionStrategy;
		$this->policyFilter = $policyFilter;
	}
	
	/**
	 * Resolves the value of a parameter given a resolution context
	 *
	 * @param ResolutionContext $resolution
	 * @return void
	 */
	public function resolveValue(ResolutionContext $resolution)
	{
		$session = $resolution->getSession();
		$policies = $this->getMatchingPolicies($resolution);
		if($this->multiInjectionStrategy->shouldMultiInject($resolution)) {
			$values = array();
			foreach($policies as $policy) {
				$values[] = $policy->get(ParameterPolicy::OPTION_REFERENCE)->getValue($session);
			}
			$resolution->setValue($values);
			$resolution->setResolved(true);
		} else {
			$policy = array_shift($policies);
			if(!is_null($policy)) {
				$resolution->setValue($policy->get(ParameterPolicy::OPTION_REFERENCE)->getValue($session));
				$resolution->setResolved(true);
			}
		}
	}
	
	/**
	 *
	 *
	 * @param ResolutionContext $resolution
	 * @return ParameterPolicy[]
	 */
	protected function getMatchingPolicies(ResolutionContext $resolution)
	{
		$parameter = $resolution->getParameter();
		$session = $resolution->getSession();
		
		// Gather all potential matches
		$policies = new SplObjectStorage();
		// Merge any matching sets of parameter policies
		$setPolicies = $this->policyFilter->getParameterSetPolicies($resolution);
		foreach($setPolicies as $setPolicy) {
			$policies->addAll($setPolicy->getParameterPolicies());
		}
		// Merge single parameter policies
		$policies->addAll($session->getPoliciesByType('Slipstream\Configuration\ParameterPolicy'));
		
		// Filter out non-matches
		$matchingPolicies = array();
		foreach($policies as $policy) {
			if($policy->matchesReflection($parameter)) {
				$matchingPolicies[] = $policy;
			}
		}
		return $matchingPolicies;
	}
}